﻿// <copyright file="InformationCardSTSServiceHosts.cs" company="SharpSTS">
// Copyright (c) 2007, 2008 All Right Reserved, http://sharpsts.com/
//
// This source is subject to the Microsoft Permissive License.
// Please see the License.txt file for more information.
// All other rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// </copyright>
// <author>Barry Dorrans</author>
// <email>barryd@idunno.org</email>
// <date>2008-06-14</date>
// <summary>Provides start, stop and host information for STS service hosts.</summary>

namespace SharpSTS.Windows
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Security.Cryptography;
    using System.Security.Cryptography.X509Certificates;
    using System.ServiceModel;
    
    using CardControl;
    using Configuration;
    using Properties;

    /// <summary>
    /// Provides host creation and shutdown processes.
    /// </summary>
    /// <remarks>
    /// This is generally used in command line or service hosted environments.
    /// </remarks>
    public static class InformationCardSTSServiceHosts
    {
        /// <summary>
        /// A list of service hosts.
        /// </summary>
        private static readonly List<ServiceHost> hostList = new List<ServiceHost>();

        /// <summary>
        /// Gets the service hosts.
        /// </summary>
        /// <value>The service hosts.</value>
        public static ReadOnlyCollection<ServiceHost> ServiceHosts
        {
            get
            {
                return hostList.AsReadOnly();
            }
        }

        /// <summary>
        /// Gets or sets the signing certificate for the services.
        /// </summary>
        /// <value>The signing certificate.</value>
        private static X509Certificate2 SigningCertificate
        {
            get;
            set;
        }

        /// <summary>
        /// Creates and opens the SharpSTS services.
        /// </summary>
        public static void Open()
        {
            string thumbprint = STSSettings.Settings.CertificateThumbprint;
            if (string.IsNullOrEmpty(thumbprint))
            {
                throw new ArgumentException(Resources.ErrorMissingThumbprint);
            }

            X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
            store.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection collection = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, true);
            if (collection.Count == 0)
            {
                throw new CryptographicException(Resources.ErrorCertificateNotFound);
            }

            if (collection.Count > 1)
            {
                throw new CryptographicException(Resources.ErrorMultipleCertificates);
            }

            SigningCertificate = collection[0];

            Uri[] baseAddresses = new[] 
                {
                    STSSettings.Settings.BaseSTSAddress, STSSettings.Settings.BaseMetadataExchangeAddress
                };

            hostList.Add(new InformationCardSTSServiceHost(typeof(UserNameAuthSTS), baseAddresses, SigningCertificate));
            hostList.Add(new InformationCardSTSServiceHost(typeof(SelfIssuedSamlAuthSTS), baseAddresses, SigningCertificate));
            hostList.Add(new CardControlServiceHost(baseAddresses));
            
            hostList.ForEach(host => host.Open());
        }

        /// <summary>
        /// Closes all open and non-faulted services.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage(
            "Microsoft.Design", 
            "CA1031:DoNotCatchGeneralExceptionTypes",
            Justification = "This is a global close method and by design catches any exception and aborts the WCF host.")]
        public static void Close()
        {
            foreach (ServiceHost host in hostList)
            {
                try
                {
                    if (host.State != CommunicationState.Closed)
                    {
                        host.Close();
                    }
                }
                catch
                {
                    host.Abort();
                }
            }
        }
    }
}
